package com.shark.uh.utils;

public class SnowflakeIDGenerator {

    // 起始时间戳 (自定义 epoch)
    private final long epoch = 1672502400000L; // 2023-01-01 00:00:00

    // 机器ID相关
    private final long machineIdBits = 10L;    // 机器ID占用位数
    private final long maxMachineId = ~(-1L << machineIdBits); // 最大机器ID值：1023

    // 序列号相关
    private final long sequenceBits = 12L;    // 序列号占用位数
    private final long maxSequence = ~(-1L << sequenceBits); // 最大序列号值：4095

    // 位移
    private final long machineIdShift = sequenceBits;               // 机器ID左移位数
    private final long timestampShift = sequenceBits + machineIdBits; // 时间戳左移位数

    private final long machineId;   // 当前机器ID
    private long sequence = 0L;     // 当前毫秒内序列号
    private long lastTimestamp = -1L; // 上一次生成ID的时间戳

    // 构造方法
    public SnowflakeIDGenerator(long machineId) {
        if (machineId < 0 || machineId > maxMachineId) {
            throw new IllegalArgumentException(String.format("Machine ID must be between 0 and %d", maxMachineId));
        }
        this.machineId = machineId;
    }

    // 生成唯一ID
    public synchronized long generateId() {
        long currentTimestamp = System.currentTimeMillis();

        if (currentTimestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate ID.");
        }

        if (currentTimestamp == lastTimestamp) {
            // 同一毫秒内，增加序列号
            sequence = (sequence + 1) & maxSequence;
            if (sequence == 0) {
                // 如果序列号用尽，等待下一毫秒
                while (currentTimestamp <= lastTimestamp) {
                    currentTimestamp = System.currentTimeMillis();
                }
            }
        } else {
            // 不同毫秒重置序列号
            sequence = 0L;
        }

        lastTimestamp = currentTimestamp;

        // 拼接ID
        return ((currentTimestamp - epoch) << timestampShift) | // 时间戳部分
                (machineId << machineIdShift) |                  // 机器ID部分
                sequence;                                        // 序列号部分
    }
}

